package net.stogi.unicore.beyond.ui.client.taskeditor.taskoutline;

import java.util.ArrayList;
import java.util.List;

import net.stogi.common.mvp.core.behavior.Behavior;
import net.stogi.common.mvp.core.behavior.BehaviorWithValue;

import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.data.BaseTreeModel;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.widget.Composite;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanel;

class TaskOutlineWidget extends Composite implements TaskOutlineView {

	private class TaskTreeModel extends BaseTreeModel {

		private static final long serialVersionUID = 6255455052868577134L;

		public TaskTreeModel(String name) {
			set("name", name);
		}

		public String getName() {
			return get("name");
		}
	}

	private final Button deleteButton = new Button();
	
	private final Button editButton = new Button();

	private final List<TaskTreeModel> inputDefinitionItems = new ArrayList<TaskTreeModel>();

	private final List<TaskTreeModel> inputGroupItems = new ArrayList<TaskTreeModel>();

	private final TaskTreeModel inputsItem = new TaskTreeModel("Inputs");

	private final ContentPanel mainPanel = new ContentPanel();

	private final ToolBar mainToolBar = new ToolBar();

	private final Button moveDownButton = new Button();

	private final Button moveUpButton = new Button();

	private final List<TaskTreeModel> outputDefinitionItems = new ArrayList<TaskTreeModel>();

	private final List<TaskTreeModel> outputGroupItems = new ArrayList<TaskTreeModel>();

	private final TaskTreeModel outputsItem = new TaskTreeModel("Outputs");

	private final TaskTreeModel rootItem = new TaskTreeModel("Task");

	private final TreePanel<TaskTreeModel> taskTreePanel;

	private final TreeStore<TaskTreeModel> taskTreeStore = new TreeStore<TaskTreeModel>();

	public TaskOutlineWidget() {
		taskTreePanel = new TreePanel<TaskTreeModel>(taskTreeStore);
		initModel();
		initComposite();
		initI18n();
		initLayout();
		initComponent(mainPanel);
	}

	@Override
	public void addInputDefinition(String definitionName, int definitionIndex, int groupIndex) {
		doAddInputDefinitionItem(definitionName, definitionIndex, groupIndex);
	}

	@Override
	public void addInputGroup(String groupName, int groupIndex) {
		doAddInputGroupItem(groupName, groupIndex);
	}

	@Override
	public void addOutputDefinition(String definitionName, int definitionIndex, int groupIndex) {
		doAddOutputDefinitionItem(definitionName, definitionIndex, groupIndex);
	}

	@Override
	public void addOutputGroup(String groupName, int groupIndex) {
		doAddOutputGroupItem(groupName, groupIndex);
	}

	@Override
	public void blockDelete(boolean block) {
		deleteButton.setEnabled(!block);
	}

	@Override
	public void blockEdit(boolean block) {
		editButton.setEnabled(!block);
	}

	@Override
	public void blockMoveDown(boolean block) {
		moveDownButton.setEnabled(!block);
	}

	@Override
	public void blockMoveUp(boolean block) {
		moveUpButton.setEnabled(!block);
	}

	@Override
	public void clear() {
		inputsItem.removeAll();
		inputGroupItems.clear();
		inputDefinitionItems.clear();
		outputsItem.removeAll();
		outputGroupItems.clear();
		outputDefinitionItems.clear();
		doInitTaskTreeStore();
	}

	@Override
	public void selectInputDefinition(String name) {
		doSelectTaskTreeItemByName(name, inputDefinitionItems);
	}

	@Override
	public void selectInputGroup(String name) {
		doSelectTaskTreeItemByName(name, inputGroupItems);
	}

	@Override
	public void selectOutputDefinition(String name) {
		doSelectTaskTreeItemByName(name, outputDefinitionItems);		
	}

	@Override
	public void selectOutputGroup(String name) {
		doSelectTaskTreeItemByName(name, outputGroupItems);
	}

	@Override
	public void setDeleteInputDefinitionBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(deleteButton, behavior, inputDefinitionItems);
	}

	@Override
	public void setDeleteInputGroupBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(deleteButton, behavior, inputGroupItems);
	}

	@Override
	public void setDeleteOutputDefinitionBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(deleteButton, behavior, outputDefinitionItems);
	}

	@Override
	public void setDeleteOutputGroupBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(deleteButton, behavior, outputGroupItems);
	}

	@Override
	public void setEditInputDefinitionBehavior(BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(editButton, behavior, inputDefinitionItems);
	}

	@Override
	public void setEditInputGroupBehavior(BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(editButton, behavior, inputGroupItems);
	}

	@Override
	public void setEditOutputDefinitionBehavior(BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(editButton, behavior, outputDefinitionItems);
	}

	@Override
	public void setEditOutputGroupBehavior(BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(editButton, behavior, outputGroupItems);
	}

	@Override
	public void setInputDefinitionSelectedBehavior(final BehaviorWithValue<String> behavior) {
		doSetSelectBehaviorBasedOnCollection(behavior, inputDefinitionItems);
	}

	@Override
	public void setInputGroupSelectedBehavior(final BehaviorWithValue<String> behavior) {
		doSetSelectBehaviorBasedOnCollection(behavior, inputGroupItems);
	}

	@Override
	public void setMoveDownInputDefinitionBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveDownButton, behavior, inputDefinitionItems);
	}

	@Override
	public void setMoveDownInputGroupBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveDownButton, behavior, inputGroupItems);
	}

	@Override
	public void setMoveDownOutputDefinitionBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveDownButton, behavior, outputDefinitionItems);
	}

	@Override
	public void setMoveDownOutputGroupBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveDownButton, behavior, outputGroupItems);
	}

	@Override
	public void setMoveUpInputDefinitionBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveUpButton, behavior, inputDefinitionItems);
	}

	@Override
	public void setMoveUpInputGroupBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveUpButton, behavior, inputGroupItems);
	}

	@Override
	public void setMoveUpOutputDefinitionBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveUpButton, behavior, outputDefinitionItems);
	}

	@Override
	public void setMoveUpOutputGroupBehavior(final BehaviorWithValue<String> behavior) {
		doSetButtonBehaviorBasedOnCollection(moveUpButton, behavior, outputGroupItems);
	}

	@Override
	public void setOutputDefinitionSelectedBehavior(final BehaviorWithValue<String> behavior) {
		doSetSelectBehaviorBasedOnCollection(behavior, outputDefinitionItems);
	}

	@Override
	public void setOutputGroupSelectedBehavior(final BehaviorWithValue<String> behavior) {
		doSetSelectBehaviorBasedOnCollection(behavior, outputGroupItems);
	}

	@Override
	public void setSomethingElseSelectedBehavior(final Behavior behavior) {
		taskTreePanel.getSelectionModel().addSelectionChangedListener(new SelectionChangedListener<TaskTreeModel>() {

			@Override
			public void selectionChanged(SelectionChangedEvent<TaskTreeModel> se) {
				TaskTreeModel selectedItem = se.getSelectedItem();
				if (selectedItem != null && !inputGroupItems.contains(selectedItem) && !inputDefinitionItems.contains(selectedItem)
						&& !outputGroupItems.contains(selectedItem) && !outputDefinitionItems.contains(selectedItem)) {
					behavior.behave();
				}
			}
		});
	}

	private void doAddInputDefinitionItem(String definitionName, int definitionIndex, int groupIndex) {
		TaskTreeModel inputDefinitionItem = new TaskTreeModel(definitionName);
		inputGroupItems.get(groupIndex).getChildren().add(definitionIndex, inputDefinitionItem);
		inputDefinitionItems.add(inputDefinitionItem);
		doInitTaskTreeStore();
	}

	private void doAddInputGroupItem(String groupName, int groupIndex) {
		TaskTreeModel inputGroupItem = new TaskTreeModel(groupName);
		inputsItem.getChildren().add(groupIndex, inputGroupItem);
		inputGroupItems.add(groupIndex, inputGroupItem);
		doInitTaskTreeStore();
	}

	private void doAddOutputDefinitionItem(String definitionName, int definitionIndex, int groupIndex) {
		TaskTreeModel outputDefinitionItem = new TaskTreeModel(definitionName);
		outputGroupItems.get(groupIndex).getChildren().add(definitionIndex, outputDefinitionItem);
		outputDefinitionItems.add(outputDefinitionItem);
		doInitTaskTreeStore();
	}

	private void doAddOutputGroupItem(String groupName, int groupIndex) {
		TaskTreeModel outputGroupItem = new TaskTreeModel(groupName);
		outputsItem.getChildren().add(groupIndex, outputGroupItem);
		outputGroupItems.add(groupIndex, outputGroupItem);
		doInitTaskTreeStore();
	}

	private void doInitTaskTreeStore() {
		taskTreeStore.removeAll();
		taskTreeStore.add(rootItem, true);
		taskTreePanel.expandAll();
	}
	
	private void doSelectTaskTreeItemByName(String name, List<TaskTreeModel> list) {
		assert name != null;
		assert list != null;
		TaskTreeModel selectedItem = null;
		for (TaskTreeModel item : list) {
			if (name.equals(item.getName())) {
				selectedItem = item;
				break;
			}
		}
		taskTreePanel.getSelectionModel().select(selectedItem, false);
	}
	
	private void doSetButtonBehaviorBasedOnCollection(Button button, final BehaviorWithValue<String> behavior, final List<TaskTreeModel> list) {
		button.addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				TaskTreeModel selectedItem = taskTreePanel.getSelectionModel().getSelectedItem();
				if (selectedItem != null && list.contains(selectedItem)) {
					behavior.behave(selectedItem.getName());
				}
			}
		});
	}

	private void doSetSelectBehaviorBasedOnCollection(final BehaviorWithValue<String> behavior, final List<TaskTreeModel> list) {
		taskTreePanel.getSelectionModel().addSelectionChangedListener(new SelectionChangedListener<TaskTreeModel>() {

			@Override
			public void selectionChanged(SelectionChangedEvent<TaskTreeModel> se) {
				TaskTreeModel selectedItem = se.getSelectedItem();
				if (selectedItem != null && list.contains(selectedItem)) {
					behavior.behave(selectedItem.getName());
				}
			}
		});
	}

	private void initComposite() {
		deleteButton.setEnabled(false);
		editButton.setEnabled(false);
		moveDownButton.setEnabled(false);
		moveUpButton.setEnabled(false);

		mainPanel.setFrame(true);
		mainPanel.setBodyStyle("background: white;");
		taskTreePanel.setAutoExpand(true);
		taskTreePanel.setBorders(true);
		taskTreePanel.setDisplayProperty("name");
		taskTreePanel.setHeight(250);
		taskTreePanel.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
		doInitTaskTreeStore();
	}

	private void initI18n() {
		deleteButton.setText("Delete");
		editButton.setText("Edit");
		moveDownButton.setText("Down");
		moveUpButton.setText("Up");
		mainPanel.setHeading("Task Outline");
	}

	private void initLayout() {
		mainToolBar.add(moveUpButton);
		mainToolBar.add(moveDownButton);
		mainToolBar.add(editButton);
		mainToolBar.add(deleteButton);
		mainPanel.setTopComponent(mainToolBar);
		mainPanel.add(taskTreePanel);
	}

	private void initModel() {
		rootItem.add(new TaskTreeModel("Main"));
		rootItem.add(inputsItem);
		rootItem.add(outputsItem);
	}
}
